"""
用户画像生成模块 (User Profiler)

基于用户行为会话和访问统计，调用 LLM 生成用户画像。
Stage 1 MVP: 使用 URL + Title + 停留时间 + 交互类型进行分析。
"""

import os
import json
import logging
from typing import Dict, Any, List, Optional
import requests

logger = logging.getLogger(__name__)


class UserProfiler:
    """用户画像生成器"""

    def __init__(self):
        """初始化用户画像生成器"""
        # 从环境变量读取 LLM 配置
        self.provider = os.getenv('LLM_PROVIDER', 'deepseek')
        self.api_key = os.getenv('LLM_API_KEY', '')
        self.api_url = os.getenv('LLM_API_URL', 'https://api.deepseek.com/v1/chat/completions')
        self.model = os.getenv('LLM_MODEL', 'deepseek-chat')
        self.timeout = int(os.getenv('LLM_TIMEOUT', '60'))

    def is_available(self) -> bool:
        """检查 LLM 是否可用"""
        return bool(self.api_key and self.api_url)

    def generate_profile(
        self,
        sessions: List[Dict[str, Any]],
        url_stats: List[Dict[str, Any]]
    ) -> Dict[str, Any]:
        """
        生成用户画像

        Args:
            sessions: 会话列表（来自 SessionDetector）
            url_stats: URL 统计列表（来自 SessionDetector）

        Returns:
            用户画像结果：
            {
                'success': True/False,
                'profile': {
                    'occupation': '职业/角色',
                    'skills': ['技能1', '技能2', ...],
                    'interests': ['兴趣1', '兴趣2', ...],
                    'current_task': '当前任务/目标',
                    'confidence': 0.0-1.0
                },
                'llm_response': 'LLM 原始响应',
                'error': '错误信息（如果失败）'
            }
        """
        if not self.is_available():
            return {
                'success': False,
                'error': 'LLM 未配置或不可用（LLM_API_KEY 缺失）'
            }

        try:
            # 构建分析 Prompt
            prompt = self._build_profile_prompt(sessions, url_stats)

            # 调用 LLM
            llm_response = self._call_llm(prompt)

            # 解析响应
            profile = self._parse_llm_response(llm_response)

            return {
                'success': True,
                'profile': profile,
                'llm_response': llm_response
            }

        except Exception as e:
            logger.error(f"生成用户画像失败: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def _build_profile_prompt(
        self,
        sessions: List[Dict[str, Any]],
        url_stats: List[Dict[str, Any]]
    ) -> str:
        """
        构建用户画像分析 Prompt

        Args:
            sessions: 会话列表
            url_stats: URL 统计

        Returns:
            Prompt 字符串
        """
        # 会话信息
        session_info = []
        for i, session in enumerate(sessions, 1):
            is_main = '⭐ 主要会话' if session['duration_sec'] > 60 else ''
            session_text = f"""
【会话{i}】 {session['start_time_str']} - {session['end_time_str']} ({session['duration_sec']}分钟) {is_main}
- 事件数量: {session['event_count']} 个
- 事件类型: {', '.join(f'{k}×{v}' for k, v in session['event_types'].items())}
- 访问页面:"""

            # 添加该会话访问的每个 URL
            for url in session['urls']:
                # 从 url_stats 中找到对应的标题和统计
                url_stat = next((s for s in url_stats if s['url'] == url), None)
                if url_stat:
                    titles = url_stat['titles']
                    title = titles[0] if titles else 'N/A'

                    # 找到该 URL 在当前会话的停留时间
                    session_visit = next(
                        (v for v in url_stat['visit_sessions'] if v['session_id'] == session['session_id']),
                        None
                    )
                    duration = session_visit['duration_sec'] if session_visit else 0

                    session_text += f"\n  · {url}\n    标题: {title}\n    停留: {duration}分钟"
                else:
                    session_text += f"\n  · {url}"

            session_info.append(session_text)

        sessions_text = '\n'.join(session_info)

        # URL 统计信息（按访问次数排序，取前10个）
        top_urls = sorted(url_stats, key=lambda x: x['total_duration_sec'], reverse=True)[:10]
        url_summary = []
        for url_stat in top_urls:
            title = url_stat['titles'][0] if url_stat['titles'] else 'N/A'
            url_summary.append(
                f"- {url_stat['url']}\n"
                f"  标题: {title}\n"
                f"  访问次数: {url_stat['visit_count']} 次\n"
                f"  总停留: {url_stat['total_duration_sec']}秒 (平均 {url_stat['avg_duration_sec']}秒/次)\n"
                f"  交互事件: {url_stat['event_count']} 个"
            )

        urls_text = '\n'.join(url_summary)

        # 构建完整 Prompt
        prompt = f"""请根据以下用户浏览行为数据，分析用户的特征画像。

# 会话详情
{sessions_text}

# URL 访问统计（按停留时间排序）
{urls_text}

# 分析要求
请从以下维度分析用户特征：
1. **职业/角色** (occupation): 用户最可能的职业或角色（如：软件开发者、产品经理、学生等）
2. **技能栈** (skills): 用户具备的技能或使用的技术（列表形式，如：["Python", "数据分析", "Kafka"]）
3. **兴趣领域** (interests): 用户感兴趣的主题领域（列表形式，如：["开源项目", "JSON处理", "云计算"]）
4. **当前任务/目标** (current_task): 用户在这些会话中试图完成什么任务
5. **兴趣深度分类** (interest_depth): 将访问的内容分为：
   - core_interests: 核心兴趣（停留 > 2分钟 + 有主动交互）
   - moderate_interests: 中等兴趣（停留 1-2分钟 或 有一定交互）
   - low_interests: 浅层浏览（停留 < 1分钟 + 交互少）
6. **置信度** (confidence): 分析结果的可信度评分（0.0-1.0），基于数据量和行为模式的清晰度

# 输出格式
请以 JSON 格式返回分析结果（不要使用 markdown 代码块）：
{{
  "occupation": "职业/角色",
  "skills": ["技能1", "技能2", ...],
  "interests": ["兴趣1", "兴趣2", ...],
  "current_task": "当前任务描述",
  "interest_depth": {{
    "core_interests": ["URL或主题1", "URL或主题2", ...],
    "moderate_interests": [...],
    "low_interests": [...]
  }},
  "confidence": 0.85,
  "reasoning": "简要说明分析依据（2-3句话）"
}}

注意：
- 基于实际数据推断，不要过度臆测
- 停留时间和交互类型是重要判断依据
- 如果数据不足以判断某项，可以留空或标注"不确定"
"""

        return prompt

    def _call_llm(self, prompt: str) -> str:
        """
        调用 LLM API

        Args:
            prompt: 输入 Prompt

        Returns:
            LLM 响应文本
        """
        if self.provider in ['openai', 'deepseek']:
            return self._call_openai_compatible(prompt)
        elif self.provider == 'claude':
            return self._call_claude(prompt)
        else:
            raise ValueError(f"不支持的 LLM Provider: {self.provider}")

    def _call_openai_compatible(self, prompt: str) -> str:
        """调用 OpenAI 兼容 API"""
        headers = {
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json'
        }

        payload = {
            'model': self.model,
            'messages': [
                {'role': 'user', 'content': prompt}
            ],
            'temperature': 0.3,
            'max_tokens': 2000  # 用户画像需要更长的输出
        }

        response = requests.post(
            self.api_url,
            headers=headers,
            json=payload,
            timeout=self.timeout
        )
        response.raise_for_status()

        result = response.json()
        return result['choices'][0]['message']['content']

    def _call_claude(self, prompt: str) -> str:
        """调用 Claude API"""
        headers = {
            'x-api-key': self.api_key,
            'anthropic-version': '2023-06-01',
            'Content-Type': 'application/json'
        }

        payload = {
            'model': self.model,
            'messages': [
                {'role': 'user', 'content': prompt}
            ],
            'max_tokens': 2000,
            'temperature': 0.3
        }

        response = requests.post(
            self.api_url,
            headers=headers,
            json=payload,
            timeout=self.timeout
        )
        response.raise_for_status()

        result = response.json()
        return result['content'][0]['text']

    def _parse_llm_response(self, response: str) -> Dict[str, Any]:
        """
        解析 LLM 响应

        Args:
            response: LLM 原始响应

        Returns:
            解析后的用户画像字典
        """
        try:
            # 去除可能的 markdown 代码块标记
            response = response.strip()
            if response.startswith('```json'):
                response = response[7:]
            if response.startswith('```'):
                response = response[3:]
            if response.endswith('```'):
                response = response[:-3]
            response = response.strip()

            # 解析 JSON
            profile = json.loads(response)
            return profile

        except json.JSONDecodeError as e:
            logger.warning(f"LLM 响应不是有效的 JSON，尝试提取: {e}")
            # 如果解析失败，返回原始响应
            return {
                'raw_response': response,
                'parse_error': str(e)
            }

    def generate_profile_with_content(
        self,
        sessions: List[Dict[str, Any]],
        url_stats: List[Dict[str, Any]],
        events: List[Dict[str, Any]]
    ) -> Dict[str, Any]:
        """
        生成用户画像（Stage 2 - 包含页面内容提取）

        Args:
            sessions: 会话列表
            url_stats: URL 统计
            events: 原始事件列表（用于内容提取）

        Returns:
            用户画像结果（格式同 generate_profile）
        """
        if not self.is_available():
            return {
                'success': False,
                'error': 'LLM 未配置或不可用（LLM_API_KEY 缺失）'
            }

        try:
            # 导入内容提取器
            from .content_extractor import ContentExtractor
            extractor = ContentExtractor()

            # 为每个URL提取页面内容（只提取主要会话的核心URL）
            url_contents = {}
            for url_stat in url_stats[:5]:  # 只处理前5个访问最多的URL
                url = url_stat['url']

                # 找到该URL的最后一个事件（通常内容最完整）
                url_events = [e for e in events if e.get('url') == url]
                if url_events:
                    last_event = url_events[-1]
                    content_result = extractor.extract_page_content(last_event, max_length=1000)
                    url_contents[url] = content_result

            # 构建包含内容的 Prompt
            prompt = self._build_stage2_prompt(sessions, url_stats, url_contents)

            # 调用 LLM
            llm_response = self._call_llm(prompt)

            # 解析响应
            profile = self._parse_llm_response(llm_response)

            return {
                'success': True,
                'profile': profile,
                'llm_response': llm_response,
                'stage': 2,
                'content_extracted': len(url_contents)
            }

        except Exception as e:
            logger.error(f"生成用户画像失败（Stage 2）: {e}")
            return {
                'success': False,
                'error': str(e)
            }

    def _build_stage2_prompt(
        self,
        sessions: List[Dict[str, Any]],
        url_stats: List[Dict[str, Any]],
        url_contents: Dict[str, Dict[str, Any]]
    ) -> str:
        """
        构建 Stage 2 的 Prompt（包含页面实际内容）

        Args:
            sessions: 会话列表
            url_stats: URL 统计
            url_contents: URL -> 内容提取结果的映射

        Returns:
            Prompt 字符串
        """
        # 会话信息（简化版）
        session_info = []
        for i, session in enumerate(sessions, 1):
            is_main = '⭐ 主要会话' if session['duration_sec'] > 60 else ''
            session_text = f"""
【会话{i}】 {session['start_time_str']} - {session['end_time_str']} ({session['duration_sec']}秒) {is_main}
- 事件数: {session['event_count']} 个
- 访问页面: {len(session['urls'])} 个"""
            session_info.append(session_text)

        sessions_text = '\n'.join(session_info)

        # URL 内容详情
        content_details = []
        for url, content in url_contents.items():
            # 从 url_stats 中获取统计信息
            stat = next((s for s in url_stats if s['url'] == url), None)
            if not stat:
                continue

            title = content['title']
            main_content = content['main_content']
            duration = stat['total_duration_sec']
            event_count = stat['event_count']

            content_details.append(f"""
【{title}】
- URL: {url}
- 停留时间: {duration}秒
- 交互事件: {event_count}个
- 页面内容摘要:
{main_content}
""")

        contents_text = '\n'.join(content_details)

        # 构建完整 Prompt
        prompt = f"""请根据以下用户浏览行为和页面内容，深入分析用户特征。

# 会话概览
{sessions_text}

# 页面内容详情（按重要性排序）
{contents_text}

# 分析要求
请结合**会话行为**和**页面实际内容**，从以下维度分析：

1. **职业/角色** (occupation): 用户的职业或角色
2. **技能栈** (skills): 用户具备的具体技能（从页面内容推断）
3. **兴趣领域** (interests): 用户真正感兴趣的主题（基于内容而非仅URL）
4. **当前任务/目标** (current_task): 用户在执行的具体任务（从内容推断）
5. **兴趣深度分类** (interest_depth):
   - core_interests: 核心兴趣（深度阅读的内容主题）
   - moderate_interests: 中等兴趣
   - low_interests: 浅层浏览
6. **关键洞察** (key_insights): 从页面内容中发现的关键信息（如：用户正在研究某个具体技术、关注某个开源项目的特定功能等）
7. **置信度** (confidence): 0.0-1.0

# 输出格式
请以 JSON 格式返回（不要使用 markdown 代码块）：
{{
  "occupation": "职业/角色",
  "skills": ["技能1", "技能2", ...],
  "interests": ["兴趣1", "兴趣2", ...],
  "current_task": "当前任务描述",
  "interest_depth": {{
    "core_interests": ["主题1", "主题2", ...],
    "moderate_interests": [...],
    "low_interests": [...]
  }},
  "key_insights": ["洞察1", "洞察2", ...],
  "confidence": 0.85,
  "reasoning": "分析依据（2-3句话）"
}}

注意：
- **重点关注页面实际内容**，而不仅仅是 URL 和标题
- 从内容中提取具体的技术、项目、主题信息
- 如果内容提到具体的代码、项目、功能，请在分析中体现
"""

        return prompt
